package com.cinnamon.rss.logic;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.Charset;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.List;
import java.util.Locale;

import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.Characters;
import javax.xml.stream.events.XMLEvent;

import com.cinnamon.rss.model.Feed;
import com.cinnamon.rss.model.Item;

public class RSSFeedParser {

	private static final String TITLE = "title";
	private static final String LINK = "link";
	private static final String DESCRIPTION = "description";
	private static final String PUB_DATE = "pubDate";
	private static final String ITEM = "item";
	private String feedUrl = ""; // rss_source_link

	private enum Tag {
		tELSE, tITEM, tTITLE, tDESCRIPTION, tLINK, tPUB_DATE
	}

	final URL url;

	public RSSFeedParser(String feedUrl) {
		try {
			this.url = new URL(feedUrl);
			this.feedUrl = feedUrl; // save feedUrl to set it in feed later
		} catch (MalformedURLException e) {
			throw new RuntimeException(e);
		}
	}

	public Feed readFeed() {
		Feed feed = null;
		List<Item> feedItems = null;
		Tag tag = null;
		try {
			boolean isFeedHeader = true;
			String title = "";
			String link = "";
			String description = "";
			String pubdate = "";
			XMLInputFactory inputFactory = XMLInputFactory.newInstance();

			InputStream in = read();
			XMLEventReader eventReader = inputFactory.createXMLEventReader(in);

			while (eventReader.hasNext()) {
				XMLEvent event = eventReader.nextEvent();
				if (event.isStartElement()) {
					String localPart = event.asStartElement().getName()
							.getLocalPart();
					System.out.println(localPart);
					tag = Tag.tELSE;
					if (localPart.equals(ITEM))
						tag = Tag.tITEM;
					if (localPart.equals(TITLE))
						tag = Tag.tTITLE;
					if (localPart.equals(DESCRIPTION))
						tag = Tag.tDESCRIPTION;
					if (localPart.equals(LINK))
						tag = Tag.tLINK;
					if (localPart.equals(PUB_DATE))
						tag = Tag.tPUB_DATE;

					System.out.println("tag is: " + tag);
					switch (tag) {
					// item
					case tITEM:
						System.out
								.println("**************************** in case ITEM ****************************");
						if (isFeedHeader) {
							System.out
									.println("**************************** before new Feed() ****************************");
							isFeedHeader = false;
							feed = new Feed(title, link, description, pubdate,
									feedUrl);
							feedItems = feed.getItems();
						}
						event = eventReader.nextEvent();
						break;
					// title
					case tTITLE:
						System.out
								.println("**************************** in case TITLE ****************************");
						title = getCharacterData(event, eventReader);
						break;
					// descr.
					case tDESCRIPTION:
						System.out
								.println("**************************** in case DESCRIPTION ****************************");
						description = getCharacterData(event, eventReader);
						break;
					// link
					case tLINK:
						System.out
								.println("**************************** in case LINK ****************************");
						link = getCharacterData(event, eventReader);
						System.out.println("link: " + link);
						break;
					// pub_date
					case tPUB_DATE:
						System.out
								.println("**************************** in case PUB_DATE ****************************");
						pubdate = getCharacterData(event, eventReader);
						break;

					}
				} else if (event.isEndElement()) {
					if ((event.asEndElement().getName().getLocalPart())
							.equals(ITEM)) {
						long longPubDate = 0;
						try {
							longPubDate = convertoToLong(pubdate);
						} catch (Exception e) {
							e.printStackTrace();
						}
						Item item = new Item(title, link, description,
								longPubDate);
						feedItems.add(item);
						event = eventReader.nextEvent();
						continue;
					}
				}
			}
			Collections.reverse(feedItems);
		} catch (XMLStreamException e) {
			throw new RuntimeException(e);
		} catch (UnsupportedEncodingException uee) {
			uee.printStackTrace();
		}
		System.out.println(feed);
		return feed;
	}

	private String getCharacterData(XMLEvent event, XMLEventReader eventReader)
			throws XMLStreamException, UnsupportedEncodingException {
		String result = "";
		String temp = "";
		event = eventReader.nextEvent();
		if (event instanceof Characters) {
			result = event.asCharacters().getData(); // encoding=cp1251
		}
		return result;
	}

	private InputStream read() {
		try {
			return url.openStream();
		} catch (IOException e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}
	}

	/*
	 * Converts date string representation to long
	 */
	public long convertoToLong(String date) throws Exception {
		DateFormat df = null;
		long newDate = 0;
		if (Character.isDigit(date.charAt(date.length() - 1))) {
			df = new SimpleDateFormat("EEE, dd MMM yyy HH:mm:ss Z", Locale.US);
			newDate = df.parse(date).getTime();
		} else {
			df = new SimpleDateFormat("EEE, dd MMM yyy HH:mm:ss zzz", Locale.US);
			newDate = df.parse(date).getTime();
		}
		return newDate;
	}

}
